// 接口

// 第一个接口示例
interface LabeledValue {
  label: string
}

function printLabelValue(labelObject: LabeledValue): void {
  console.log(labelObject.label);
}

// 类型检查器检查对  printLabelValue 参数的调用
// printLabelValue 函数有一个参数，该参数要求传入的对象具有一个名为 string 类型的 label 的属性。
// 我们传入的对象可以有其他属性，但是：必须要有一个名为 label 的 string 类型的属性，否则会报错
let myObj2 = { size: 10, label: "Size 10 Object" };
printLabelValue(myObj2);


// Optional Properties 可选属性
interface ShapeConfig {
  name: string;
  color?: string;
  width?: number;
  height?: number
}

function createShape(config: ShapeConfig): { name: string, area: number } {

  let newShape = { name: 'square', color: 'white', width: 10, height: 10, area: 100 };

  if (config.color) {
    newShape.color = config.color;
  }

  if (config.width) {
    newShape.width = config.width;
  }

  if (config.height) {
    newShape.height = config.height;
  }

  newShape.area = newShape.width * newShape.height;

  return newShape;
}

let myShape = createShape({ name: 'mySquare', color: "red" });

// Readonly properties 只读属性
interface Point {
  readonly x: number;
  readonly y: number;
}

let point1: Point = { x: 10, y: 20 };

// 给只读属性重新赋值会报错
// error TS2540: Cannot assign to 'x' because it is a read-only property.
// point1.x = 10;

// TS 中使用 ReadonlyArray<T> 只读数组来存储只读的属性，类似 Array<T>，只是在此基础上删除了属性的可修改的方法
let a1: number[] = [1, 2, 3, 4];
let ro1: ReadonlyArray<number> = a1;

// 失败
// ro1[0] = 0;
// ro1.push(5);
// ro1.length = 10;
// a1 = ro1;


// Function Types 函数的类型
interface SearchFunc2 {
  (source: string, substring: string): boolean;
}

let mySearchFun: SearchFunc2;

mySearchFun = function(source: string, substring: string): boolean {
  return source.search(substring) > -1;
}

// 为了使函数类型可以正确的检查，参数的名称不需要匹配
let mySeatchFun2: SearchFunc2;
mySeatchFun2 = function(src: string, sub: string): boolean {
  return src.search(sub) > -1;
}

// 如果不指定参数的类型和返回值类型，TS 会根据上下文进行类型推断
let mySearch3: SearchFunc2;
mySearch3 = function(src, sub) {
  // 如果返回值类型是数字或者字符串，TS的类型检查器会报错：提示返回类型与SearchFunc2接口描述的类型不匹配
  return src.search(sub) > -1;
}

// Indexable Types 可索引类型
interface StringArray2 {
  [index: number]: string
}

let myArr: StringArray2;
myArr = ["Tom", "Jerry"];
console.log(myArr[0])

// 支持的索引签名有两种类型，数字和字符串
interface Animal2 {
  name: string
}

interface Dog2 extends Animal2 {
  breed: string
}

interface NotOkay2 {
  // [x: number]: Animal2;
  [x: string]: Dog2;
}

